package main

import (
	"context"
	"gitee.com/kinwyb/appTools/appTool"
	"gitee.com/kinwyb/appTools/log"
	"gitee.com/kinwyb/appTools/manager"
	"gitee.com/kinwyb/conv"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"
)

var useUpx = false
var defaultAppDir = "./app"

var app = appTool.NewApplication("manager")

func main() {
	appTool.Version = "1.1.5"
	app.SetAppDescription("应用管理服务端")
	app.IgnoreConfigCheck()
	//app.FlagParseRpcxServerAddr()
	app.Flag().StringVarP(&defaultAppDir, "path", "p", "./app", "运行文件目录")
	app.Flag().StringVarP(&httpListenAddress, "http", "l", "0.0.0.0:9999", "http监听地址")
	app.Flag().StringVarP(&tcpListenAddress, "tcp", "t", "0.0.0.0:9998", "tcp监听地址")
	app.Flag().BoolVarP(&useUpx, "enableUpx", "u", false, "是否启用upx压缩")
	app.PrepareFunc(func(application *appTool.Application) {
		httpLists := strings.SplitN(httpListenAddress, ":", 2)
		app.EnableHttp(httpLists[0], conv.ToIntDefault(httpLists[1], 9999))
		log.AppTool.Info("HTTP监听开启:" + httpListenAddress)
		app.Http().Swagger(&appTool.RestfulSwaggerConfig{
			Title:    "接口文件",
			Version:  appTool.Version,
			BasePath: "/v1",
			Host:     httpLists[0],
			Schemes:  []string{"http"},
		})
		initHttp(app.Http())
	}).RunFunc(func(ctx context.Context) {
		go checkVersionGoroutine(ctx)
		initTcpServer(ctx)
	}).Run()
}

// 执行文件信息
type execFileInfo struct {
	fileName string `description:"应用名称"`
	os       string `description:"操作系统"`
	version  string `description:"版本号"`
}

// 执行文件map[应用名称]array[执行文件信息]
var execMapMutex = sync.RWMutex{}
var execMap = map[string][]execFileInfo{}

func checkVersionGoroutine(ctx context.Context) {
	checkVersion(defaultAppDir, nil)
	t := time.NewTicker(1 * time.Minute)
	for {
		select {
		case <-t.C:
			checkVersion(defaultAppDir, nil)
		case <-ctx.Done():
			return
		}
	}
}

// 检测版本信息
func checkVersion(dir string, newExecMap map[string][]execFileInfo) {
	dir, _ = filepath.Abs(dir)
	rd, err := ioutil.ReadDir(dir)
	if err != nil {
		manager.ServiceLog.WithError(err).Error("获取运行目录文件失败")
		return
	}
	if newExecMap == nil {
		newExecMap = make(map[string][]execFileInfo)
	}
	for _, fi := range rd {
		//log.AppTool.Infof("获取执行程序[%s]版本", fi.Name())
		if fi.IsDir() {
			checkVersion(filepath.Join(dir, fi.Name()), newExecMap)
		} else if !strings.HasPrefix(fi.Name(), ".") {
			appName := strings.Split(strings.Split(fi.Name(), "@")[0], "_")[0]
			execInfo := execFileInfo{
				fileName: fi.Name(),
				os:       runtime.GOOS,
				version:  "0.0.0",
			}
			c := exec.Command(filepath.Join(dir, fi.Name()), "version")
			c.Dir = dir
			ver, err := c.Output()
			if err != nil {
				//log.AppTool.Infof("[%s]exec获取失败:%s", fi.Name(), err.Error())
				vs := strings.SplitN(fi.Name(), "_", 2)
				if len(vs) < 2 {
					//log.AppTool.Infof("[%s]版本异常", fi.Name())
					continue
				}
				ds := strings.SplitN(vs[1], "@", 2)
				execInfo.os = ds[0]
				if len(ds) > 1 {
					execInfo.version = strings.TrimRight(ds[1], ".exe")
				}
			} else {
				execInfo.version = string(ver)
			}
			execInfo.version = strings.TrimSpace(execInfo.version)
			if useUpx { //启用upx压缩
				upx(fi.Name(), dir)
			}
			newExecMap[appName] = append(newExecMap[appName], execInfo)
			//log.AppTool.Infof("[%s]版本 => %s", fi.Name(), appName)
		}
	}
	execMapMutex.Lock()
	execMap = newExecMap
	execMapMutex.Unlock()
	//data, _ := json.Marshal(execMap)
	//log.AppTool.Info(string(data))
	//log.AppTool.Infof("[%s]执行程序版本信息结束:%v", dir, execMap)
}

// upx压缩
func upx(fileName string, dir string) {
	// 检测是否已经upx压缩
	c := exec.Command("upx", "-t", fileName)
	c.Dir = dir
	result, _ := c.Output()
	if len(result) > 0 {
		resultString := string(result)
		if strings.Contains(resultString, "testing "+fileName+" [OK]") {
			return
		}
	}
	// 压缩
	c = exec.Command("upx", fileName)
	c.Dir = dir
	c.Run()
}

// 获取程序版本
func getVersion(appName string, os string) string {
	execMapMutex.RLock()
	vs := execMap[appName]
	execMapMutex.RUnlock()
	for _, v := range vs {
		if v.os == os {
			return v.version
		}
	}
	return ""
}
